function ppg_gui_filter()

    % Create app window
    app.UIFigure = uifigure('Name', 'PPG Notch Filter GUI', ...
                            'Position', [300 100 900 700]);

    % Globals for shared access
    global Fs t raw noisy filtered;
    Fs = 125;

    % Axes for Time Domain
    app.UIAxesTime = uiaxes(app.UIFigure, ...
        'Position', [50 360 800 250]);
    title(app.UIAxesTime, 'Time Domain');  % Set title separately
    xlabel(app.UIAxesTime, 'Time (s)');
    ylabel(app.UIAxesTime, 'Amplitude');
    grid(app.UIAxesTime, 'on');

    % Axes for Frequency Domain
    app.UIAxesFreq = uiaxes(app.UIFigure, ...
        'Position', [50 50 800 250]);
    title(app.UIAxesFreq, 'Frequency Domain');  % Set title separately
    xlabel(app.UIAxesFreq, 'Frequency (Hz)');
    ylabel(app.UIAxesFreq, 'Magnitude');
    grid(app.UIAxesFreq, 'on');

    % Load CSV Button
    uibutton(app.UIFigure, ...
        'Text', 'Load CSV File', ...
        'Position', [100 640 180 30], ...
        'ButtonPushedFcn', @(btn, event) loadCSV());

    % Filter Button
    uibutton(app.UIFigure, ...
        'Text', 'Apply Notch Filter', ...
        'Position', [320 640 200 30], ...
        'ButtonPushedFcn', @(btn, event) applyFilter());

    %% Nested functions
    function loadCSV()
        [file, path] = uigetfile('*.csv', 'Select PPG CSV File');
        if isequal(file, 0), return; end

        raw = csvread(fullfile(path, file));
        t = (0:length(raw)-1) / Fs;
        noise60 = 0.5 * sin(2 * pi * 60 * t);
        noisy = raw(:)' + noise60;

        % Plot noisy signal
        plot(app.UIAxesTime, t, noisy, 'r');
        title(app.UIAxesTime, 'PPG Signal with 60 Hz Noise');
    end

    function applyFilter()
        if isempty(noisy)
            uialert(app.UIFigure, 'Load the CSV file first.', 'Error');
            return;
        end

        wo = 60 / (Fs/2);
        bw = wo / 35;
        [b, a] = iirnotch(wo, bw);
        filtered = filter(b, a, noisy);

        % Time-domain
        plot(app.UIAxesTime, t, noisy, 'r'); hold(app.UIAxesTime, 'on');
        plot(app.UIAxesTime, t, filtered, 'b');
        title(app.UIAxesTime, 'Noisy vs Filtered');
        legend(app.UIAxesTime, 'Noisy', 'Filtered');
        hold(app.UIAxesTime, 'off');

        % Frequency-domain
        n = length(noisy);
        f = (0:n-1) * (Fs/n);
        fft_noisy = abs(fft(noisy));
        fft_filtered = abs(fft(filtered));

        plot(app.UIAxesFreq, f, fft_noisy, 'r'); hold(app.UIAxesFreq, 'on');
        plot(app.UIAxesFreq, f, fft_filtered, 'b');
        xlim(app.UIAxesFreq, [0 62.5]);
        title(app.UIAxesFreq, 'Frequency Spectrum');
        legend(app.UIAxesFreq, 'Noisy', 'Filtered');
        hold(app.UIAxesFreq, 'off');
    end
end
